﻿using System;
using System.Xml;
using SdmxMl.Helper;
using System.Windows.Forms;
using System.Collections.Generic;
using SdmxMl.Common;

namespace SdmxMl.Structure
{
    /// <summary>
    /// CodeType defines the structure of a code. This allows for plain-text descriptions as element content, 
    /// and the coded value as the value attribute. (Short descriptions or other presentational information may be added 
    /// using Annotations with an indicative type field [eg, "ShortDescription"]). The urn attribute supplies a valid 
    /// SDMX Registry URN (see the SDMX Registry Specification).The parentCode attribute provides the ability to describe 
    /// simple hierarchies within a single codelist, by referenceing the id value of another code in the same codelist.
    /// </summary>
    public class CodeType : BaseArtefact, ISdmxHierarchyListItem
    {
        #region Properties

        public Uri Urn  { get; set; }
        public string Uri { get; set; }

        public string Parent { get; set; }
       
        // No use for flat hierarchy
        public IHierarchyManage InnerHierarchy
        {
            get { return null; }
        }

        #endregion //Properties

        #region Constructors

        public CodeType()
        {
            Id = "Undefined";
        }

        public CodeType(XmlNode nodeArtefact, SdmxNamespaceManager nsmgr)
            : base(nodeArtefact, nsmgr)
        {
            // IN SDMX 2.0 the id is named value, the description is the Name & the annotation of type NOTE
            // is the description.
            if (nsmgr.VersionSdmx == SdmxVersion.SDMX_20)
            {
                Id = Xmlhelper.GetAtt(nodeArtefact, "value");
                Name = Description.Clone();
                Description.Clear();
                Annotation ann = AnnotationList.GetAnnotationType("NOTE");
                if (ann != null)
                {
                    Description = ann.Text.Clone();
                    AnnotationList.Remove(ann);
                }
                ann = AnnotationList.GetAnnotationType("URI");
                if (ann != null)
                {
                    Uri = ann.Title;
                    AnnotationList.Remove(ann);
                }
                /*
                Annotation an = AnnotationList.GetAnnotationType("Schulart_guAb");
                if (an != null)
                {
                    an.Title = an.Text.ToString();
                    an.Text.UpdateDefaultText(string.Empty);
                }
                an = AnnotationList.GetAnnotationType("Schulart_guBis");
                if (an != null)
                {
                    an.Title = an.Text.ToString();
                    an.Text.UpdateDefaultText(string.Empty);
                }
                 */
                //AnnotationList anl = AnnotationList.GetAllAnnotationOfType("EXCLUSION", null);
                //foreach (Annotation a in anl)
                //    a.Type = "EXCLUDE";

                // Parent given as node attribute
                Parent = Xmlhelper.GetAtt(nodeArtefact, "parentCode");

                // Bridge export exclude language if same, correct
                //BridgeCorrect(Name);

            }
            else // SDMX 2.1
            {
                // Parent given as node
                string query = "./structure:Parent/Ref";
                XmlNode ndParent = nodeArtefact.SelectSingleNode(query, nsmgr);
                if (ndParent != null)
                    Parent = Xmlhelper.GetAtt(ndParent, "id");
                else
                {
                    // TODO ny URN
                }

                // SDMX 2.1 only
                Uri = Xmlhelper.GetAtt(nodeArtefact, "uri");
            }

            // Common 2.0 and 2.1
            string urn = Xmlhelper.GetAtt(nodeArtefact, "urn");
            if (UrlValidator.IsValidUrl(urn))
                Urn = new Uri(urn);
        }

        private void BridgeCorrect(MultiLang m)
        {
            if (!m.IsEmpty && !m.AllSame)
            {
                string prev = string.Empty;
                int ndx = 0;
                foreach (string lg in LangSupport.SupportedLanguages)
                {
                    string cur = m.GetForLanguage(lg);
                    if (ndx > 0)
                    {
                        if (cur == MultiLang.UndefinedText)
                        {
                            m.UpdateForLanguage(lg, prev);
                            cur = prev;
                        }
                    }
                    prev = cur;
                    ++ndx;
                }
            }
        }
        #endregion //Constructors

        #region Clone

        public ISdmxHierarchyListItem Clone()
        {
            CodeType c = new CodeType();
            c.Id = Id;
            c.Name = Name.Clone();
            c.Description = Description.Clone();
            c.Uri = Uri;
            if (Urn != null)
                c.Urn = new Uri(Urn.ToString());

            c.AnnotationList = AnnotationList.Clone();
            c.Parent = string.Empty;

            return c;
        }
        #endregion

        #region XML serialize

        public void WriteXml(XmlTextWriter xw, string prefix, string tag)
        {
            /*
            Annotation aState = AnnotationList.GetAnnotationType("SG_STAAT");
            if (aState != null && aState.Text.GetFirst() == "N")
                return;
             */

            xw.WriteStartElement(prefix, tag, null);

            if (SdmxNamespaceManager.SdmxTarget == SdmxVersion.SDMX_21)
            {
                // Attributes
                xw.WriteAttributeString("id", Id);
                if (Urn != null)
                    Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn.ToString());
                Xmlhelper.WriteAttributeIfExist(xw, "uri", Uri);

                AnnotationList.WriteXml(xw, "common", null);
                Name.WriteXml(xw, prefix, "Name");
                Description.WriteXml(xw, prefix, "Description");

                if (string.IsNullOrEmpty(Parent) == false)
                {
                    xw.WriteStartElement(prefix, "Parent", null);
                    xw.WriteStartElement("Ref");
                    xw.WriteAttributeString("id", Parent);
                    xw.WriteEndElement();
                    xw.WriteEndElement();
                }

            }
            else // SDMX 2.0
            {
                // value required
                xw.WriteAttributeString("value", Id);
                if (Urn != null)
                    Xmlhelper.WriteAttributeIfExist(xw, "urn", Urn.ToString());

                Xmlhelper.WriteAttributeIfExist(xw, "parentCode", Parent);

                // Name required
                if (Name.IsEmpty)
                    Name.TextList.Add(new TextType(LangSupport.CurLang, "Undefined"));
                Name.WriteXml(xw, prefix, "Description");

                Annotation annDescr = null;
                Annotation annUri = null;
                // Support new SDMX 2.1 attributes as Annotations
                if (Description.IsEmpty == false)
                {
                    annDescr = new Annotation("NOTE");
                    annDescr.Text = Description;
                    AnnotationList.Insert(0, annDescr);
                }
                if (string.IsNullOrEmpty(Uri) == false)
                {
                    annUri = new Annotation("URI");
                    annUri.Title = Uri;
                    AnnotationList.Insert(0, annUri);
                }

                AnnotationList.WriteXml(xw, prefix, null);
                if (annDescr != null)
                    AnnotationList.Remove(annDescr);
                if (annUri != null)
                    AnnotationList.Remove(annUri);
            }
            
            xw.WriteEndElement();
        }

        #endregion // XML serialize

        #region Tree

        public override TreeNode FillNode(TreeNode parentNode)
        {
            TreeNode t = new TreeNode(this.ToString());
            t.Tag = this;
            parentNode.Nodes.Add(t);
            return t;
        }

        #endregion // Tree

        #region String Representation

        public override string ToString()
        {
            return Id + " - " + Name.ToString();
        }

        #endregion
    }

    #region Item comparison Class

    /// <summary>
    /// Helper For numeric coderef ordering
    /// </summary>
    public class ItemCompareNum : IComparer<ISdmxHierarchyListItem>
    {

        public int Compare(ISdmxHierarchyListItem x, ISdmxHierarchyListItem y)
        {
            int rep = 0;
            if (x != null && y != null)
            {
                if (NumHelper.isNumeric(x.Id, System.Globalization.NumberStyles.Integer) &&
                    NumHelper.isNumeric(y.Id, System.Globalization.NumberStyles.Integer))
                {
                    rep = System.Convert.ToInt32(x.Id) - System.Convert.ToInt32(y.Id);
                }

                else
                {
                    rep = x.Id.CompareTo(y.Id);
                }
            }
            return rep;
        }
    }
    #endregion

    #region Code Container Class

    public class CodeList : FlatHierarchicalList
    {
        public CodeList()
            : base("Code", "Description")
        {
        }

        public override ISdmxHierarchyListItem CreateNewItem()
        {
            return new CodeType();
        }

        public override ISdmxHierarchyListItem CreateNewItem(XmlNode nd, SdmxNamespaceManager nsmgr)
        {
            return new CodeType(nd, nsmgr);
        }

        public override string ToString()
        {
            return "Codes";
        }
    }
    #endregion

}
